Contents
  1. 1. 介绍
    1. 1.1. 补1:
    2. 1.2. 补2:
  2. 2. 深度拷贝工具类:

参考:http://www.cnblogs.com/mengdd/archive/2013/02/20/2917971.html
《改善java程序的151个建议》

介绍

  • 把对象写到流里的过程是序列化过程(Serialization),而把对象从流中读出来的过程则叫做反序列化过程(Deserialization)。写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

  • 在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

补1:

用此方法进行对象拷贝时需要注意一下两点:

(1) 对象的内部属性都是可序列化的
  如果有内部属性不可序列化,则会抛出序列化异常,CloneUtiles工具类的异常要进行细化处理。

(2) 注意方法和属性的特殊修饰符
  比如final,static变量的序列化问题会被映入到对象拷贝里来,这点需要注意。同时transient变量也会影响拷贝的效果。(反序列化时不会执行构造函数,所以final变量别在构造函数中赋值,对象序列化不关注类的静态变量)

补2:

  可以使用Apache下的commons工具包中的SerializationUtils类,直接使用更加简洁方便。

先来个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class Teacher3 implements Serializable
{

private static final long serialVersionUID = 123L;
private String name;
private int age;

public String getName()
{

return name;
}

public void setName(String name)
{

this.name = name;
}

public int getAge()
{

return age;
}

public void setAge(int age)
{

this.age = age;
}

}

class Student3 implements Serializable
{

private static final long serialVersionUID = 123L;
private String name;
private int age;
private Teacher3 teacher;

public String getName()
{

return name;
}

public void setName(String name)
{

this.name = name;
}

public int getAge()
{

return age;
}

public void setAge(int age)
{

this.age = age;
}

public Teacher3 getTeacher()
{

return teacher;
}

public void setTeacher(Teacher3 teacher)
{

this.teacher = teacher;
}

public Student3 deepClone() throws Exception//深度拷贝
{

Student3 cloneObject = null;
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(this);
oos.close();

// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);

cloneObject = (Student3)ois.readObject();
ois.close();

return cloneObject;
}

}


public class Lian4 {

public static void main(String[] args) throws Exception
{

Teacher3 t = new Teacher3();
t.setName("Teacher Wang");
t.setAge(50);

Student3 s1 = new Student3();
s1.setAge(20);
s1.setName("ZhangSan");
s1.setTeacher(t);

Student3 s2 = s1.deepClone();

System.out.println("拷贝得到的信息:");
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("---------------------------");

// 将复制后的对象的老师信息修改一下:
s2.getTeacher().setName("New Teacher Wang");
s2.getTeacher().setAge(28);

System.out.println("修改了拷贝对象的教师后:");
System.out.println("拷贝对象的教师:");
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("原来对象的教师:");
System.out.println(s1.getTeacher().getName());
System.out.println(s1.getTeacher().getAge());

// 序列化的方式实现了对象的深拷贝

}
}

输出:
拷贝得到的信息:
ZhangSan
20
Teacher Wang
50
---------------------------
修改了拷贝对象的教师后:
拷贝对象的教师:
New Teacher Wang
28
原来对象的教师:
Teacher Wang
50

深度拷贝工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class CloneUtiles{
//请不要正常的或用反射实例化工具类
private CloneUtiles() {}

@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T obj){

T cloneObject = null;
try{
//读取对象字节数据
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
//把对象写到流里(序列化)
oos.writeObject(obj);
oos.close();

//分配内存空间,写入原始对象,生成新对象
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
//反序列化,从流里读出来,重建对象
cloneObject = (T)ois.readObject();
ois.close();

}catch(Exception e){
e.printStackTrace();
}

return cloneObject;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
下面来运用下这个工具类:
package yu;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

class CloneUtiles{
//请不要正常的或用反射实例化工具类
private CloneUtiles() {}

@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T obj){

T cloneObject = null;
try{
//读取对象字节数据
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
//把对象写到流里(序列化)
oos.writeObject(obj);
oos.close();

//分配内存空间,写入原始对象,生成新对象
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
//反序列化
cloneObject = (T)ois.readObject();
ois.close();

}catch(Exception e){
e.printStackTrace();
}

return cloneObject;
}

}

class Teacher3 implements Serializable
{

private static final long serialVersionUID = 123L;
private String name;
private int age;

public String getName()
{

return name;
}

public void setName(String name)
{

this.name = name;
}

public int getAge()
{

return age;
}

public void setAge(int age)
{

this.age = age;
}

}

class Student3 implements Serializable
{

private static final long serialVersionUID = 123L;
private String name;
private int age;
private Teacher3 teacher;

public String getName()
{

return name;
}

public void setName(String name)
{

this.name = name;
}

public int getAge()
{

return age;
}

public void setAge(int age)
{

this.age = age;
}

public Teacher3 getTeacher()
{

return teacher;
}

public void setTeacher(Teacher3 teacher)
{

this.teacher = teacher;
}
}


public class Lian4 {

public static void main(String[] args) throws Exception
{

Teacher3 t = new Teacher3();
t.setName("Teacher Wang");
t.setAge(50);

Student3 s1 = new Student3();
s1.setAge(20);
s1.setName("ZhangSan");
s1.setTeacher(t);

Student3 s2 = CloneUtiles.deepClone(s1);

System.out.println("拷贝得到的信息:");
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("---------------------------");

// 将复制后的对象的老师信息修改一下:
s2.getTeacher().setName("New Teacher Wang");
s2.getTeacher().setAge(28);

System.out.println("修改了拷贝对象的教师后:");
System.out.println("拷贝对象的教师:");
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("原来对象的教师:");
System.out.println(s1.getTeacher().getName());
System.out.println(s1.getTeacher().getAge());


}
}
输出:
拷贝得到的信息:
ZhangSan
20
Teacher Wang
50
---------------------------
修改了拷贝对象的教师后:
拷贝对象的教师:
New Teacher Wang
28
原来对象的教师:
Teacher Wang
50
Contents
  1. 1. 介绍
    1. 1.1. 补1:
    2. 1.2. 补2:
  2. 2. 深度拷贝工具类: